import {parser} from "./syntax.js"
import {LRLanguage, LanguageSupport, indentNodeProp, foldNodeProp, foldInside, delimitedIndent} from "@codemirror/language"
import {styleTags, tags as t} from "@lezer/highlight"
import {EditorState} from "@codemirror/state"
import {Decoration, DecorationSet, EditorView, ViewPlugin, ViewUpdate} from "@codemirror/view"

// 自定义插件来处理没有TID:前缀的TID格式、参数类型、SQL语句和括号包围的类路径
const customHighlightPlugin = ViewPlugin.fromClass(class {
  decorations: DecorationSet

  constructor(view: EditorView) {
    this.decorations = this.buildDecorations(view)
  }

  update(update: ViewUpdate) {
    if (update.docChanged || update.viewportChanged)
      this.decorations = this.buildDecorations(update.view)
  }

  buildDecorations(view: EditorView) {
    const widgets: any[] = []
    const doc = view.state.doc
    
    for (let i = 1; i <= doc.lines; i++) {
      const line = doc.line(i)
      const text = line.text
      
      // 匹配没有TID:前缀的TID格式 [xxx.xxx.xxx]
      const tidRegex = /\[([a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*(\.[0-9]+)*)\]/g
      let match
      
      while ((match = tidRegex.exec(text)) !== null) {
        const from = line.from + match.index
        const to = from + match[0].length
        const content = match[1]
        
        // 检查是否不是标准的TID格式
        if (!content.startsWith('TID:') && !content.startsWith('tid:')) {
          // 检查是否不是已知的日志级别
          const isLogLevel = /^(FATAL|ERROR|INFO|WARNING|DEBUG|WARN)$/i.test(content)
          if (!isLogLevel) {
            widgets.push({
              from: from,
              to: to,
              decoration: Decoration.mark({
                class: "cm-literal"
              }).range(from, to)
            })
          }
        }
      }
      
      // 匹配参数类型格式：xxx (String), xxx (Long), xxx (Integer), xxx (Boolean)
      // 修改正则表达式以支持数字开头的参数名
      const paramTypeRegex = /\b([a-zA-Z0-9_]+)\s*\(([A-Z][a-zA-Z]*)\)/g
      while ((match = paramTypeRegex.exec(text)) !== null) {
        const from = line.from + match.index
        const to = from + match[0].length
        const paramType = match[2]  // 参数类型：String, Long, Integer, Boolean等
        
        // 根据参数类型使用不同的CSS类名
        const cssClass = `cm-sql-param-type-${paramType}`
        
        widgets.push({
          from: from,
          to: to,
          decoration: Decoration.mark({
            class: cssClass
          }).range(from, to)
        })
      }
      
      // 匹配SQL语句：SELECT|UPDATE|INSERT|DELETE|CREATE|DROP|ALTER|WHERE|FROM
      const sqlRegex = /\s(SELECT|UPDATE|INSERT|DELETE|CREATE|DROP|ALTER|WHERE|FROM)\s/gi
      while ((match = sqlRegex.exec(text)) !== null) {
        const from = line.from + match.index + 1  // +1 跳过前面的空格
        const to = from + match[1].length  // 只包含关键字，不包括后面的空格
        
        widgets.push({
          from: from,
          to: to,
          decoration: Decoration.mark({
            class: "cm-keyword-sql"
          }).range(from, to)
        })
      }
      
      // 匹配数值：
      // - 等号后的数字始终高亮，例如 key=123
      // - 冒号后的数字仅在冒号前不是数字时高亮，例如 aaa:123 高亮；123:123 不高亮；开头的 :20799 不高亮
      // 1) 处理等号
      const numberAfterEqRegex = /=\s*(\d+)/g
      while ((match = numberAfterEqRegex.exec(text)) !== null) {
        const number = match[1]
        const from = line.from + match.index + 1 + (match[0].length - 1 - number.length) // 跳过 '=' 和空格
        const to = from + number.length
        widgets.push({
          from,
          to,
          decoration: Decoration.mark({ class: "cm-number" }).range(from, to)
        })
      }

      // 2) 处理冒号（前一个字符不是数字时才高亮）
      const numberAfterColonRegex = /(^|[^0-9]):\s*(\d+)/g
      while ((match = numberAfterColonRegex.exec(text)) !== null) {
        const prefixLen = match[1] ? match[1].length : 0
        const number = match[2]
        const from = line.from + match.index + prefixLen + 1 + (match[0].length - prefixLen - 1 - number.length) // 跳过前缀、':' 和空格
        const to = from + number.length
        widgets.push({
          from,
          to,
          decoration: Decoration.mark({ class: "cm-number" }).range(from, to)
        })
      }

      // 3) 括号内数字（支持可选正负号）：高亮内部数字（含符号），排除括号本身，例如 (1)/(-1)/(+10)
      const parenNumberRegex = /\(([+-]?\d+)\)/g
      while ((match = parenNumberRegex.exec(text)) !== null) {
        const from = line.from + match.index + 1
        const to = from + match[1].length
        widgets.push({
          from,
          to,
          decoration: Decoration.mark({ class: "cm-number" }).range(from, to)
        })
      }

      // 4) 方括号内数字（支持可选正负号）：高亮内部数字（含符号），排除方括号本身，例如 [1]/[-1]/[+10]
      const bracketNumberRegex = /\[([+-]?\d+)\]/g
      while ((match = bracketNumberRegex.exec(text)) !== null) {
        const from = line.from + match.index + 1
        const to = from + match[1].length
        widgets.push({
          from,
          to,
          decoration: Decoration.mark({ class: "cm-number" }).range(from, to)
        })
      }
      
      // 匹配类路径：各种格式的类路径
      // 1. 括号包围的类路径：(com.cn.yft.ora.bank.p600030.points.PointsProcessor:64) 或 :?
      const classPathRegex1 = /\(([a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+:(\d+|\?))\)/g
      while ((match = classPathRegex1.exec(text)) !== null) {
        const from = line.from + match.index + 1  // +1 跳过左括号
        const to = from + match[1].length  // 只包含括号内的内容
        
        widgets.push({
          from: from,
          to: to,
          decoration: Decoration.mark({
            class: "cm-typeName"
          }).range(from, to)
        })
      }
      
      // 2. 方括号包围的类路径：[com.cn.yft.ora.bank.sby.service.SBYBaseService] 或附带 :数字 或 :?
      const classPathRegex2 = /\[([a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+(:(\d+|\?))?)\]/g
      while ((match = classPathRegex2.exec(text)) !== null) {
        const from = line.from + match.index + 1  // +1 跳过左方括号
        const to = from + match[1].length  // 只包含方括号内的内容
        
        widgets.push({
          from: from,
          to: to,
          decoration: Decoration.mark({
            class: "cm-typeName"
          }).range(from, to)
        })
      }
      
      // 3. 裸类路径（边界限定），可选附带 :数字 或 :?；前后允许为空白/括号/破折号边界
      // 捕获组1为前缀边界，组2为类路径主体
      const classPathRegex3 = /(^|[\s\[\(])([a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+)(?=[\s\-:\)\]]|$)/g
      while ((match = classPathRegex3.exec(text)) !== null) {
        const from = line.from + match.index + match[1].length  // 跳过前缀边界
        const to = from + match[2].length  // 只包含类路径主体
        
        widgets.push({
          from: from,
          to: to,
          decoration: Decoration.mark({
            class: "cm-typeName"
          }).range(from, to)
        })
      }
      
      // 4. 裸类路径 + 行号或? ：com.xxx.Class:123 或 com.xxx.Class:?
      const classPathWithLineRegex = /(^|[\s\[\(])([a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+:(\d+|\?))(?=[\s\-\)\]]|$)/g
      while ((match = classPathWithLineRegex.exec(text)) !== null) {
        const from = line.from + match.index + match[1].length
        const to = from + match[2].length
        
        widgets.push({
          from: from,
          to: to,
          decoration: Decoration.mark({
            class: "cm-typeName"
          }).range(from, to)
        })
      }
    }
    
    // 按from位置排序
    widgets.sort((a, b) => a.from - b.from)
    
    // 创建装饰器集合
    const decorations = widgets.map(widget => widget.decoration)
    
    return Decoration.set(decorations)
  }
}, {
  decorations: v => v.decorations
})

export const LogLanguage = LRLanguage.define({
  parser: parser.configure({
    props: [
      styleTags({
        FATALExpression: t.heading1,
        ERRORExpression: t.heading2,
        WARNINGExpression: t.heading3,
        INFOExpression: t.heading4,
        DebugExpression: t.heading5,
        DATEExpression: t.heading6,
        TIDExpression:t.literal,
        TIDWithEmptyPrefixExpression:t.literal,
        StringLiteral: t.string,
      })
    ]
  })
})

export function Log() {
  return new LanguageSupport(LogLanguage, [
    customHighlightPlugin
  ])
}
